#pragma once
#ifndef __SHADEROBJECT_H__
#define __SHADEROBJECT_H__

#include "Utility.h"

#include "../util/PreDeclare.h"
#include "../util/D3DCommon.h"

namespace WindGE
{
	enum EShaderType
	{
		e_shader_unknow,
		e_shader_vertex,
		e_shader_hull,
		e_shader_domain,
		e_shader_geometry,
		e_shader_pixel,

		e_shader_count
	};

	class WIND_CORE_API ShaderObject
	{
	public:
		ShaderObject();
		virtual ~ShaderObject();

		bool init(RenderDevicePtr renderDevice, ShaderProgramPtr shaderProgram,
			const std::string& fileName, const std::string& funcName, const std::string& profile);

		virtual bool create() = 0;
		virtual void bind() = 0;
		virtual void unbind() = 0;

		virtual EShaderType type() const { return e_shader_unknow; }

		void update_cbuffer(ConstantBufferDataPtr bufferData);
		void bind_texture_resource(TexturePtr texture);
		void bind_texture_sampler();

	protected:
		bool compile();

		bool reflection_shader_object();
		bool reflection_constant_buffer();
		bool reflection_texture_resource();
		bool reflection_view_target();

		void output_shader_message_(ID3D10Blob* errorMsg);

		void attach_cbuffer(const std::string& name, ConstantBufferPtr cbuffer);
		void attach_texres(const std::string& name, TextureResourcePtr texres);
		void attach_texsampler(const std::string& name, TextureSamplerPtr texsampler);
		void attach_viewtarget(const std::string& name, ShaderViewTargetPtr viewtarget);

	protected:
		RenderDevicePtr				render_device_;
		std::string					file_name_;
		std::string					func_name_;
		std::string					shader_profile_;
		ShaderProgramPtr_Weak		shader_program_;
		ID3D10Blob*					buffer_;
		ID3D11ShaderReflection*		shader_reflection_;
		D3D11_SHADER_DESC			desc_;

		std::unordered_map<std::string, ConstantBufferPtr>		cbuffer_mapping_;
		std::unordered_map<std::string, TextureResourcePtr>		texres_mapping_;
		std::unordered_map<std::string, TextureSamplerPtr>		texsampler_mapping_; 
		std::unordered_map<std::string, ShaderViewTargetPtr>	view_target_mapping_;
	};

	class WIND_CORE_API VertexShader : public ShaderObject
	{
	public:
		VertexShader();
		virtual ~VertexShader();

		virtual bool create();
		virtual void bind();
		virtual void unbind();

		virtual EShaderType type() const { return e_shader_vertex; }

		inline VertexInputlayoutPtr input_layout() const { return input_layout_; }

	private:
		ID3D11VertexShader*		vertex_shader_;
		VertexInputlayoutPtr	input_layout_;
	};

	class WIND_CORE_API GeometryShader : public ShaderObject
	{
	public:
		GeometryShader();
		virtual ~GeometryShader();

		virtual bool create();
		virtual void bind();
		virtual void unbind();

		virtual EShaderType type() const { return e_shader_geometry; }

	private:
		ID3D11GeometryShader* geometry_shader_;
	};

	class WIND_CORE_API HullShader : public ShaderObject
	{ 
	public:
		HullShader();
		virtual ~HullShader();

		virtual bool create();
		virtual void bind();
		virtual void unbind();
		
		virtual EShaderType type() const { return e_shader_hull; }

	private:
		ID3D11HullShader* hull_shader_;
	};

	class WIND_CORE_API DomainShader : public ShaderObject
	{
	public:
		DomainShader();
		virtual ~DomainShader();

		virtual bool create();
		virtual void bind();
		virtual void unbind();

		virtual EShaderType type() const { return e_shader_domain; }

	private:
		ID3D11DomainShader* domain_shader_;
	};

	class WIND_CORE_API PixelShader : public ShaderObject
	{
	public:
		PixelShader();
		virtual ~PixelShader();

		virtual bool create();
		virtual void bind();
		virtual void unbind();

		virtual EShaderType type() const { return e_shader_pixel; }

	private:
		ID3D11PixelShader* pixel_shader_;
	};

}//end namespace WindGE

#endif	//__SHADEROBJECT_H__
